Super ugly number [Heap, Hash, BST]

Time: O(NxK); Space: O(N+K); medium

Write a program to find the nth super ugly number.

Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k.

Example 1:

Input: n = 12, primes = [2,7,13,19]

Output: 32

Explanation:

  • [1,2,4,7,8,13,14,16,19,26,28,32] is the sequence of the first 12 super ugly numbers

  • given primes = [2,7,13,19] of size 4.

Example 2:

Input: n = 6, primes = [2,7,13,19]

Output: 13

Example 3:

Input: n = 11, primes = [2,3,5]

Output: 15

Notes:

  • 1 is a super ugly number for any given primes.

  • The given numbers in primes are in ascending order.

  • 0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000.

  • The n-th super ugly number is guaranteed to fit in a 32-bit signed integer.

1. Heap solution [O(NxK), O(N+K)]

[3]:
import heapq

class Solution1(object):
    """
    Time: O(N*K)
    Space: O(N+K)
    """
    def nthSuperUglyNumber(self, n, primes):
        """
        :type n: int
        :type primes: List[int]
        :rtype: int
        """
        heap, uglies, idx, ugly_by_last_prime = [], [0] * n, [0] * len(primes), [0] * n
        uglies[0] = 1

        for k, p in enumerate(primes):
            heapq.heappush(heap, (p, k))

        for i in range(1, n):
            uglies[i], k = heapq.heappop(heap)
            ugly_by_last_prime[i] = k
            idx[k] += 1
            while ugly_by_last_prime[idx[k]] > k:
                idx[k] += 1
            heapq.heappush(heap, (primes[k] * uglies[idx[k]], k))

        return uglies[-1]
[4]:
s = Solution1()

n = 12
primes = [2,7,13,19]
assert s.nthSuperUglyNumber(n, primes) == 32

n = 6
primes = [2,7,13,19]
assert s.nthSuperUglyNumber(n, primes) == 13

n = 11
primes = [2,3,5]
assert s.nthSuperUglyNumber(n, primes) == 15

2. Heap solution

[5]:
import heapq

class Solution2(object):
    def nthSuperUglyNumber(self, n, primes):
        """
        :type n: int
        :type primes: List[int]
        :rtype: int
        """
        uglies, idx, heap = [1], [0] * len(primes), []
        for k, p in enumerate(primes):
            heapq.heappush(heap, (p, k))

        for i in range(1, n):
            min_val, k = heap[0]
            uglies += [min_val]

            while heap[0][0] == min_val:  # worst time: O(klogk)
                min_val, k = heapq.heappop(heap)
                idx[k] += 1
                heapq.heappush(heap, (primes[k] * uglies[idx[k]], k))

        return uglies[-1]
[6]:
s = Solution2()

n = 12
primes = [2,7,13,19]
assert s.nthSuperUglyNumber(n, primes) == 32

n = 6
primes = [2,7,13,19]
assert s.nthSuperUglyNumber(n, primes) == 13

n = 11
primes = [2,3,5]
assert s.nthSuperUglyNumber(n, primes) == 15

3.

[7]:
import heapq

class Solution3(object):
    def nthSuperUglyNumber(self, n, primes):
        """
        :type n: int
        :type primes: List[int]
        :rtype: int
        """
        ugly_number = 0

        heap = []
        heapq.heappush(heap, 1)
        for p in primes:
            heapq.heappush(heap, p)
        for _ in range(n):
            ugly_number = heapq.heappop(heap)
            for i in range(len(primes)):
                if ugly_number % primes[i] == 0:
                    for j in range(i + 1):
                        heapq.heappush(heap, ugly_number * primes[j])
                    break

        return ugly_number
[8]:
s = Solution3()

n = 12
primes = [2,7,13,19]
assert s.nthSuperUglyNumber(n, primes) == 32

n = 6
primes = [2,7,13,19]
assert s.nthSuperUglyNumber(n, primes) == 13

n = 11
primes = [2,3,5]
assert s.nthSuperUglyNumber(n, primes) == 15

4. Hash solution

[9]:
class Solution4(object):
    def nthSuperUglyNumber(self, n, primes):
        """
        :type n: int
        :type primes: List[int]
        :rtype: int
        """
        uglies, idx, heap, ugly_set = [0] * n, [0] * len(primes), [], set([1])
        uglies[0] = 1

        for k, p in enumerate(primes):
            heapq.heappush(heap, (p, k))
            ugly_set.add(p)

        for i in range(1, n):
            uglies[i], k = heapq.heappop(heap)
            while (primes[k] * uglies[idx[k]]) in ugly_set:
                idx[k] += 1
            heapq.heappush(heap, (primes[k] * uglies[idx[k]], k))
            ugly_set.add(primes[k] * uglies[idx[k]])

        return uglies[-1]
[10]:
s = Solution4()

n = 12
primes = [2,7,13,19]
assert s.nthSuperUglyNumber(n, primes) == 32

n = 6
primes = [2,7,13,19]
assert s.nthSuperUglyNumber(n, primes) == 13

n = 11
primes = [2,3,5]
assert s.nthSuperUglyNumber(n, primes) == 15

5.

[11]:
class Solution5(object):
    def nthSuperUglyNumber(self, n, primes):
        """
        :type n: int
        :type primes: List[int]
        :rtype: int
        """
        uglies = [0] * n
        uglies[0] = 1
        ugly_by_prime = list(primes)
        idx = [0] * len(primes)

        for i in range(1, n):
            uglies[i] = min(ugly_by_prime)
            for k in range(len(primes)):
                if uglies[i] == ugly_by_prime[k]:
                    idx[k] += 1
                    ugly_by_prime[k] = primes[k] * uglies[idx[k]]

        return uglies[-1]
[12]:
s = Solution5()

n = 12
primes = [2,7,13,19]
assert s.nthSuperUglyNumber(n, primes) == 32

n = 6
primes = [2,7,13,19]
assert s.nthSuperUglyNumber(n, primes) == 13

n = 11
primes = [2,3,5]
assert s.nthSuperUglyNumber(n, primes) == 15